#include "../common.h"
#include <windows.h>

static HMODULE getExeHandle()
{
    static HMODULE handle = NULL;

    // this is safe because DynamicLibrary holds a class-level lock
    if ( handle == NULL )
    {
        handle = GetModuleHandle( NULL );
    }

    return handle;
}

/*
 * Class:     com_googlecode_dni_internal_library_DynamicLibrary
 * Method:    openImpl
 * Signature: (Ljava/lang/String;)J
 */
JNIEXPORT jlong JNICALL Java_com_googlecode_dni_internal_library_DynamicLibrary_openImpl(
    JNIEnv* env,
    jclass clazz,
    jstring name )
{
    const jchar* nameStr = NULL;
    HMODULE handle;

    if ( name != NULL )
    {
        nameStr = (*env)->GetStringChars( env, name, NULL );
	    if ( nameStr == NULL )
	    {
    	    return 0;
        }
	    handle = LoadLibraryW( (wchar_t*) nameStr );
    }
    else
    {
        handle = getExeHandle();
    }

	if ( name != NULL )
    {
	    (*env)->ReleaseStringChars( env, name, nameStr );
	}

	if ( handle == NULL )
	{
		// TODO error message
	    (*env)->ThrowNew( env, (*env)->FindClass( env, "java/lang/UnsatisfiedLinkError" ), "Failed to load" );
	    return 0;
	}

	return POINTER_TO_JLONG( handle );
}

/*
 * Class:     com_googlecode_dni_internal_library_DynamicLibrary
 * Method:    getSymbolImpl
 * Signature: (JLjava/lang/String;)J
 */
JNIEXPORT jlong JNICALL Java_com_googlecode_dni_internal_library_DynamicLibrary_getSymbolImpl(
    JNIEnv* env,
    jclass clazz,
    jlong handle,
    jstring name )
{
    const char* nameStr;
    void* sym;
    char* errorStr;

    // TODO WRONG! Not UTF-8
    nameStr = (*env)->GetStringUTFChars( env, name, NULL );
	if ( nameStr == NULL )
	{
	    return 0;
	}

	sym = GetProcAddress( (HMODULE) handle, nameStr );

	if ( sym == NULL )
	{
		// TODO error message
	    (*env)->ThrowNew( env, (*env)->FindClass( env, "com/googlecode/dni/internal/library/SymbolNotFoundException" ), nameStr );
		(*env)->ReleaseStringUTFChars( env, name, nameStr );
	
	    return 0;
	}
	
	(*env)->ReleaseStringUTFChars( env, name, nameStr );
	
	return POINTER_TO_JLONG( sym );
}

/*
 * Class:     com_googlecode_dni_internal_library_DynamicLibrary
 * Method:    freeImpl
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_googlecode_dni_internal_library_DynamicLibrary_freeImpl(
    JNIEnv* env,
    jclass clazz,
    jlong handle )
{
	int result;

	if ( handle == 0 || (HMODULE) handle == getExeHandle() )
	{
        return;
	}

	result = FreeLibrary( (HMODULE) handle );
	
	if ( result == 0 )
	{
		// TODO error message
	    (*env)->ThrowNew( env, (*env)->FindClass( env, "java/lang/LinkageError" ), "Failed to free" );
	}
	
    return;
}
